﻿using Engine;
using System.Linq;
using TemplatesDatabase;
using System.Collections.Generic;
using System.Globalization;
using GameEntitySystem;
using Engine.Graphics;
using Engine.Media;
using Game;

namespace MMap
{
	public class SubsystemMMapBehaviour : SubsystemBlockBehavior, IUpdateable
	{
        public SubsystemGameInfo m_subsystemGameInfo;
        public SubsystemPickables m_subsystemPickables;
        public SubsystemAudio m_subsystemAudio;
        public PrimitivesRenderer2D m_primitivesRenderer2D = new();
        public UpdateOrder UpdateOrder => UpdateOrder.Default;
		public Dictionary<int, MMapContent> MapContents = [];
        public float m_useCd;
		public override void Load(ValuesDictionary valuesDictionary)
		{
			base.Load(valuesDictionary);
            m_subsystemGameInfo = Project.FindSubsystem<SubsystemGameInfo>();
            m_subsystemPickables = Project.FindSubsystem<SubsystemPickables>();
            m_subsystemAudio = Project.FindSubsystem<SubsystemAudio>();
            ValuesDictionary keyValuePairs1 = valuesDictionary.GetValue<ValuesDictionary>("MapContents", null);
            if (keyValuePairs1 != null)
            {
                IEnumerator<KeyValuePair<string, object>> enumerator = keyValuePairs1.GetEnumerator();
                while (enumerator.MoveNext())
                {
                    KeyValuePair<string, object> kvp = enumerator.Current;
                    if (int.TryParse(kvp.Key, out int key) && kvp.Value is Point2 value)
                    {
                        MMapContent mapContent = new(key, value);
                        if (MMapManager.LoadMapImage(m_subsystemGameInfo.DirectoryName + "/MMap", kvp.Key, ref mapContent.RenderTarget2D))
						{//成功加载图像
                            MapContents.Add(key, mapContent);
						}
                    }
                }
            }

        }
        public override void Save(ValuesDictionary valuesDictionary)
		{
			base.Save(valuesDictionary);
            ValuesDictionary valuesDictionary20 = [];
            valuesDictionary.SetValue("MapContents", valuesDictionary20);
            foreach (var item in MapContents)
            {
                valuesDictionary20.SetValue(item.Key.ToString(), item.Value.StartChunkCoords);
				MMapManager.SaveMapImage(item.Key.ToString(), ref item.Value.RenderTarget2D);
			}
        }
        public int CreateNewMapContent(Vector2 center)
        {
            int index = 1;//从1开始而不是0，因为地图data为0时表示空地图
            if (MapContents.Count > 0)
                index = MapContents.Keys.Max() + 1;
            Point2 startChunkCoords = Terrain.ToChunk(new Vector2(MathUtils.Floor(center.X / MMapContent.MapSize.X) * MMapContent.MapSize.X, MathUtils.Floor(center.Y / MMapContent.MapSize.Y) * MMapContent.MapSize.Y));
            foreach (var item in MapContents)
            {
                if (item.Value.StartChunkCoords == startChunkCoords)
                {
                    index = item.Key;
                    break;
                }
            }
            if (!MapContents.ContainsKey(index))
                MapContents.Add(index, new MMapContent(index, startChunkCoords));
            AlterMapContent(index, center);
            return index;
        }
        public void AlterMapContent(int index, Vector2 center)
        {
            if (MapContents.TryGetValue(index, out var content))
            {
                Point2 startCoords = content.StartChunkCoords, endCoords = startCoords + MMapContent.MapSize / 16 - Point2.One;
                RenderTarget2D previousTarget = Display.RenderTarget;
                Display.RenderTarget = content.RenderTarget2D;
                FlatBatch2D flatBatch_Cells = m_primitivesRenderer2D.FlatBatch(layer: 0);
                FlatBatch2D flatBatch_Shadow = m_primitivesRenderer2D.FlatBatch(layer: 1);
                var terrainChunks = SubsystemTerrain.Terrain.AllocatedChunks.Where(c => c != null /*&& c.State >= TerrainChunkState.InvalidContents4*/ && Vector2.Distance(center, c.Center) <= MMapContent.ScanRadius);
                foreach (TerrainChunk terrainChunk in terrainChunks)
                {
                    Point2 coords = terrainChunk.Coords;
                    if (coords.X >= startCoords.X && coords.Y >= startCoords.Y && coords.X <= endCoords.X && coords.Y <= endCoords.Y)
                    {
                        Vector2 chunkOriginOnPic = new Vector2(content.RenderTarget2D.Width, content.RenderTarget2D.Height) - new Vector2(coords - startCoords) * 16f;
                        for (int i = 0; i < 16; i++)
                        {
                            for (int j = 0; j < 16; j++)
                            {
                                int h = MMapManager.GetChunkTopHeight(terrainChunk, i, j, true);
                                int cellValue = terrainChunk.GetCellValueFast(i, h, j);
                                Color color = MMapManager.GetBlockColor(cellValue, SubsystemTerrain, new Point3(i + terrainChunk.Origin.X, h, j + terrainChunk.Origin.Y));
                                Vector2 corner1 = chunkOriginOnPic - new Vector2(i, j), corner2 = corner1 + Vector2.One;
                                flatBatch_Cells.QueueQuad(corner1, corner2, 0, color);

                                //if (color.A > 0)
                                {
                                    bool higherThanSouth = false;
                                    bool higherThanEast = false;
                                    if (j > 0)
                                        higherThanSouth = h > MMapManager.GetChunkTopHeight(terrainChunk, i, j - 1, true);
                                    else
                                    {
                                        TerrainChunk chunk1 = terrainChunks.ToList().Find(c => c.Coords == coords + new Point2(0, -1));
                                        if (chunk1 != null /*&& chunk1.State >= TerrainChunkState.InvalidContents4*/)
                                            higherThanSouth = h > MMapManager.GetChunkTopHeight(chunk1, i, 15, true);
                                    }
                                    if (i > 0)
                                        higherThanEast = h > MMapManager.GetChunkTopHeight(terrainChunk, i - 1, j, true);
                                    else
                                    {
                                        TerrainChunk chunk1 = terrainChunks.ToList().Find(c => c.Coords == coords + new Point2(-1, 0));
                                        if (chunk1 != null/* && chunk1.State >= TerrainChunkState.InvalidContents4*/)
                                            higherThanEast = h > MMapManager.GetChunkTopHeight(chunk1, 15, j, true);
                                    }
                                    if (higherThanSouth)
                                        flatBatch_Shadow.QueueQuad(corner1 + Vector2.UnitY, corner2 + Vector2.UnitY, 0, new Color(Color.Black, 100));
                                    if (higherThanEast)
                                        flatBatch_Shadow.QueueQuad(corner1 + Vector2.UnitX, corner2 + Vector2.UnitX, 0, new Color(Color.DarkGray, 100));
                                }
                            }
                        }
                    }
                }
                m_primitivesRenderer2D.Flush();
                Display.RenderTarget = previousTarget;
            }
        }

		public override bool OnUse(Ray3 ray, ComponentMiner componentMiner)
		{
            int value = componentMiner.Inventory.GetSlotValue(componentMiner.Inventory.ActiveSlotIndex);
            int id = Terrain.ExtractContents(value), data = Terrain.ExtractData(value);
            if (id == BlocksManager.GetBlockIndex<MMapBlock>())
            {//使用地图
                object obj = componentMiner.Raycast(ray, RaycastMode.Digging);
                if (obj is TerrainRaycastResult terrainRaycastResult)
                {
                    CellFace cellFace = terrainRaycastResult.CellFace;
                    int cellValue = SubsystemTerrain.Terrain.GetCellValue(cellFace.X, cellFace.Y, cellFace.Z), cellId = Terrain.ExtractContents(cellValue), cellData = Terrain.ExtractData(cellValue);
                    if(cellId == BlocksManager.GetBlockIndex<MMapFrameBlock>())
					{//将地图挂到展示框上
                        int hangingMapData = MMapFrameBlock.GetMapData(cellData);
                        if (hangingMapData != data)
						{//悬挂的地图与手上的地图不一样
                            if (hangingMapData > 0)
                                m_subsystemPickables.AddPickable(Terrain.MakeBlockValue(BlocksManager.GetBlockIndex<MMapBlock>(), 0, hangingMapData), 1, terrainRaycastResult.HitPoint() - 0.2f * Vector3.Normalize(ray.Direction), null, null);
                            SubsystemTerrain.ChangeCell(cellFace.X, cellFace.Y, cellFace.Z, Terrain.ReplaceData(cellValue, MMapFrameBlock.SetMapData(cellData, data)));
                            componentMiner.RemoveActiveTool(1);
                            m_subsystemAudio.PlaySound("Audio/PickableCollected", 1f, 0, ray.Position, 1f, autoDelay: true);
                            return true;
                        }
                    }
                }
                IInventory inventory = componentMiner.Inventory;
                if (data == 0)
                {
                    int num = CreateNewMapContent(componentMiner.ComponentCreature.ComponentBody.Position.XZ);
                    if (num >= 0)
                    {
                        inventory.RemoveSlotItems(inventory.ActiveSlotIndex, inventory.GetSlotCount(inventory.ActiveSlotIndex));
                        if (inventory.GetSlotCount(inventory.ActiveSlotIndex) == 0)
                        {
                            inventory.AddSlotItems(inventory.ActiveSlotIndex, Terrain.MakeBlockValue(id, 0, num), 1);
                            componentMiner.ComponentPlayer.ComponentGui.DisplaySmallMessage(LanguageControl.Get(GetType().Name, "MapCreated"), Color.White, true, true);
                        }
                    }
                }
                else
                {
                    if(m_useCd > 0)
					{
                        componentMiner.ComponentPlayer.ComponentGui.DisplaySmallMessage(LanguageControl.Get(GetType().Name, "Failed"), Color.White, true, true);
                        return false;
                    }
                    else
					{
                        AlterMapContent(data, componentMiner.ComponentCreature.ComponentBody.Position.XZ);
                        componentMiner.ComponentPlayer.ComponentGui.DisplaySmallMessage(string.Format(LanguageControl.Get(GetType().Name, "Drew"), MMapContent.ScanRadius), Color.White, true, true);
                        m_useCd = 1f;
                    }
                }
                return true;
            }
            return false;
		}

        public void Update(float dt)
		{
            m_useCd = MathUtils.Max(0, m_useCd - dt);
		}
	}
}
